/***************************************************************************
 * CLIENTAPP.CPP
 *
 *  OWebFolder: Client Application Implementation and Main Entry.
 *
 *  Copyright (c)1999-2003; Microsoft Corporation, All rights reserved.
 *  Written by DSOI Office Integration, Microsoft Developer Support
 *
 *  THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
 *  EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
 *  WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
 *
 ***************************************************************************/
#include "owebfolder.h"
#define SBAR_HEIGHT    20

COfficeWebClientApp* g_theApp = NULL;   // the main app

///////////////////////////////////////////////////////////////////////////////////
// COfficeWebClientApp
//
//  This class hosts the main Windows application interface. It is a very simple
//  design and implementation (just enough to host the folder and MSDAIPP classes).
//
COfficeWebClientApp::COfficeWebClientApp(HINSTANCE hInstance)
{
    ODS("*** COfficeWebClientApp created ***\n");
	m_hInstance      = hInstance;
	m_curArrow       = NULL;
	m_curWait        = NULL;
	m_hAccel         = NULL;
	m_hmnuMainMenu   = NULL;
	m_hwndApp        = NULL;
	m_hwndStatus     = NULL;
	m_hwndListView   = NULL;
	m_himlIcons      = NULL;
	m_himlSmIcons    = NULL;
	m_pRootFolder    = NULL;
	m_pCurrentFolder = NULL;
	m_fROSession     = FALSE;
}

COfficeWebClientApp::~COfficeWebClientApp(void)
{
    ODS("*** COfficeWebClientApp destroyed ***\n");
}

///////////////////////////////////////////////////////////////////////////////////
// COfficeWebClientApp::InitApplication
//
//  Creates the main host window, status bar, and list view, then posts a message
//  to show the Open Folder dialog after it is visible.
//
BOOL COfficeWebClientApp::InitApplication(LPCSTR pszCmdLine, int nCmdShow)
{
    WNDCLASSEX   wc;
	HICON        hico;
	LVCOLUMN     lvc; 

    TRACE1("COfficeWebClientApp::InitApplication(nCmdShow=%d)\n", nCmdShow);

	m_curArrow = LoadCursor(NULL, IDC_ARROW);
	m_curWait  = LoadCursor(NULL, IDC_WAIT);

 // 1. Register window class...
    ZeroMemory(&wc, sizeof(WNDCLASSEX));
	wc.cbSize		  = sizeof(WNDCLASSEX);
	wc.style          = CS_HREDRAW | CS_VREDRAW;
    wc.hCursor        = m_curArrow;
    wc.hInstance      = m_hInstance;
    wc.cbWndExtra     = 8;
    wc.hbrBackground  = (HBRUSH)(COLOR_APPWORKSPACE + 1);
    wc.hIcon          = LoadIcon(m_hInstance, MAKEINTRESOURCE(IDI_MAIN_ICON));
	wc.hIconSm 		  = (HICON)LoadImage(m_hInstance, MAKEINTRESOURCE(IDI_MAIN_ICON), IMAGE_ICON, 16, 16, 0);
    wc.lpszClassName  = "OWebFldWndClass";
    wc.lpfnWndProc    = ClientAppWndProc;

    if (!RegisterClassEx(&wc))
		return FALSE;

 // 2. Load Menu resources...
    m_hmnuMainMenu = LoadMenu(m_hInstance, MAKEINTRESOURCE(IDR_MAIN_MENU));
	CHECK_NULL_RETURN(m_hmnuMainMenu, FALSE);

 // 3. Load accelerators...
    m_hAccel = LoadAccelerators(m_hInstance, MAKEINTRESOURCE(IDR_ACCELERATORS));
	CHECK_NULL_RETURN(m_hAccel, FALSE);

 // 4. Create the main window and client-area window
    m_hwndApp = CreateWindow("OWebFldWndClass", "Office WebFolder Test Sample",
                          WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
						  CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
                          NULL, m_hmnuMainMenu, m_hInstance, NULL);
	CHECK_NULL_RETURN(m_hwndApp, FALSE);

 // 5. Init the common controls and create status bar...
    InitCommonControls();
    
	m_hwndStatus = CreateStatusWindow(SBARS_SIZEGRIP | WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE, "", m_hwndApp, 3);
	CHECK_NULL_RETURN(m_hwndStatus, FALSE);

 // 6. Create ListView. The view we create will be shared by multiple COfficeWebFolder
 // objects to allow for a sort of simplified caching. In this sample we don't support
 // multi-select or sorting by headers, so those flags are set here...
	m_hwndListView = CreateWindow(WC_LISTVIEW, "List",
		WS_CHILD | LVS_LIST | LVS_SINGLESEL | LVS_AUTOARRANGE | LVS_NOSORTHEADER, 0, 0, 0, 0, m_hwndApp, (HMENU)1, 0, 0);
	CHECK_NULL_RETURN(m_hwndListView, FALSE);

 // 7. Create the ImageLists. We should do more to get associated icons, but for this
 // sample we'll just load 2 -- a folder icon and a file icon...
	m_himlIcons = ImageList_Create(32, 32, ILC_MASK, 2, 0); 
	CHECK_NULL_RETURN(m_himlIcons, FALSE);

	m_himlSmIcons = ImageList_Create(16, 16, ILC_MASK, 2, 0); 
	CHECK_NULL_RETURN(m_himlSmIcons, FALSE);

	hico = LoadIcon(m_hInstance, MAKEINTRESOURCE(IDI_FILE_ICON));
	ImageList_AddIcon(m_himlIcons, hico);
 	ImageList_AddIcon(m_himlSmIcons, hico);
	
	hico = LoadIcon(m_hInstance, MAKEINTRESOURCE(IDI_FOLDER_ICON));
	ImageList_AddIcon(m_himlIcons, hico);
 	ImageList_AddIcon(m_himlSmIcons, hico);

    ListView_SetImageList(m_hwndListView, m_himlIcons, LVSIL_NORMAL); 
    ListView_SetImageList(m_hwndListView, m_himlSmIcons, LVSIL_SMALL);

 // 8. Set up the columns for the list view (shared between all COfficeWebFolder objects
 // so easy to do now in the intialization as a one-time job...
	memset(&lvc, 0, sizeof(LVCOLUMN));
	lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;

	lvc.pszText = "Name"; lvc.iSubItem = 0; lvc.cx = 180; lvc.fmt = LVCFMT_LEFT;
	ListView_InsertColumn(m_hwndListView, 0, &lvc);

	lvc.pszText = "Size"; lvc.iSubItem = 1; lvc.cx = 80; lvc.fmt = LVCFMT_RIGHT;
	ListView_InsertColumn(m_hwndListView, 1, &lvc);

	lvc.pszText = "Type"; lvc.iSubItem = 2; lvc.cx = 140; lvc.fmt = LVCFMT_LEFT;
	ListView_InsertColumn(m_hwndListView, 2, &lvc);

	lvc.pszText = "Date Modified"; lvc.iSubItem = 3;lvc.cx = 180; lvc.fmt = LVCFMT_LEFT;
	ListView_InsertColumn(m_hwndListView, 3, &lvc);

 // 9. Make us all visible.
    ShowWindow(m_hwndApp, nCmdShow);
    UpdateWindow(m_hwndApp);

 // 10. Post a message to bring up the Open Folder dialog...
	PostMessage(m_hwndApp, WM_COMMAND, IDM_OPENFOLDER, 0);
    return TRUE;
}

///////////////////////////////////////////////////////////////////////////////////
// COfficeWebClientApp::MessageLoop
//
//  Simple Win32 Message Loop (enough said)...
//
WPARAM COfficeWebClientApp::MessageLoop(void)
{
    MSG     msg;

    ODS("+ Starting message loop... +\n");
    while (GetMessage(&msg, NULL, 0, 0))
    {
      // Finally, handle the message ourselves (if not translated first)...
        if (!::TranslateAccelerator(m_hwndApp, m_hAccel, &msg))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }

    } // Keep spinning until WM_QUIT...

    TRACE1("- Exiting message loop (code =%d) -\n", msg.wParam);
    return msg.wParam;
}

///////////////////////////////////////////////////////////////////////////////////
// COfficeWebClientApp Command Functions
//
///////////////////////////////////////////////////////////////////////////////////
// COfficeWebClientApp::CmdOpenFolder
//
//  Displays a dialog to the user to allow for setting the URL and bind properties.
//  If successful, a COfficeWebFolder object will be made to display the files/folder
//  at the given URL, and allow for read/write access as requested. 
//
STDMETHODIMP_(BOOL) COfficeWebClientApp::CmdOpenFolder()
{
	MSDAIPP_SESSIONINFO sessinfo;
	CMSDAIPPSession    *pMsdaippSession = NULL;
	CMSDAIPPRowset     *pMsdaippRowset = NULL;
	HRESULT             hr = E_UNEXPECTED;
	DWORD               cbLockOwner = MAX_PATH;

    ODS("COfficeWebClientApp::CmdOpenFolder\n");

 // 1. Create an instance of the MSDAIPP DSO object. If this fails it is likely
 //    because user doesn't have Office 2000 (or higher) installed and they are
 //    not on Windows 2000 (or higher). We can't go further if provider not installed...
	pMsdaippSession = CMSDAIPPSession::CreateMsdaippDso();
 	if (pMsdaippSession == NULL)
	{
		MessageBox(m_hwndApp, "We are unable to create the DSO for MSDAIPP. Make sure you "
			"have Office 2000 (or higher) installed on the system and that the MSDAIPP "
			"provider (located in the \"C:\\Program Files\\Common Files\\System\\OLE "
			"DB\\\" folder) is properly installed and registered.", 
			"Can't create MSDAIPP!", MB_ICONHAND|MB_SETFOREGROUND);
		ODS("CMSDAIPPSession::CreateMsdaippDso failed");
        return FALSE;
	}

 // 2. Setup a MSDAIPP_SESSIONINFO struct for the dialog...
	memset(&sessinfo, 0, sizeof(MSDAIPP_SESSIONINFO));
	GetUserName(sessinfo.szLockOwner, &cbLockOwner); // User making the web requests...
	sessinfo.hwnd = m_hwndApp;               // Window handle of the main app...         
	sessinfo.lcid = GetThreadLocale();       // Current thread LCID...
	sessinfo.uiProviderVersion = pMsdaippSession->GetMsdaippVersion();

retrydialog:
 // 3. Show the OpenFolder dialog and get bind properties...
	if (DialogBoxParam(m_hInstance, MAKEINTRESOURCE(IDD_OPENFOLDERDLG),
						m_hwndApp, OpenFolderWndProc, (LONG)&sessinfo) > 0)
	{
		SetCursor(m_curWait);

	 // 4. Close any existing folder since we are about to open a new one...
		CmdCloseFolder();

	 // 5. Create a new session and Bind to the URL...
		hr = pMsdaippSession->CreateNewSession(&sessinfo);
		LEAVE_ON_ERROR(hr, "CMSDAIPPSession::CreateSession failed");

		hr = pMsdaippSession->CreateRootRowset(&pMsdaippRowset);
		LEAVE_ON_ERROR(hr, "CMSDAIPPSession::CreateRootRowset failed");

		m_fROSession = ((sessinfo.grfBindFlags & DBBINDURLFLAG_WRITE) != DBBINDURLFLAG_WRITE);

	 //  6. Create a folder and bind it to the session and our list view...
		m_pRootFolder = COfficeWebFolder::CreateWebFolderView(NULL, pMsdaippRowset, m_hwndListView);
		if (m_pRootFolder == NULL) LEAVE2(hr, E_OUTOFMEMORY, "CreateWebFolderView failed");

	 // 7. AddRef to hold on to it as the current folder...
        (m_pCurrentFolder = m_pRootFolder)->AddRef();

	 // 8. Populate the list view and make it visible...
		hr = m_pCurrentFolder->PopulateListView();
		LEAVE_ON_ERROR(hr, "Unable to populate list view");

		ShowWindow(m_hwndListView, SW_SHOW);
		SetFocus(m_hwndListView);

	 // 9. Set the URL and server type in the status bar...
        InternalSetStatusBarFolderName();

		LPSTR pszServerType = " HTTP 1.1";
		switch (pMsdaippSession->GetServerType())
		{
		case 1: pszServerType = " Office";   break;
		case 2: pszServerType = "Exchange";  break;
		case 3: pszServerType = "SPS/DAV";   break;
		case 4: pszServerType = "WEC/FPSE";  break;
		case 5: pszServerType = " WebDAV";   break;
		};
		SendMessage(m_hwndStatus, SB_SETTEXT, 1, (LPARAM)(pszServerType));

	 // 10. Set the version string of the provider for more info...
		SendMessage(m_hwndStatus, SB_SETTEXT, 2, 
			(LPARAM)(pMsdaippSession->GetMsdaippVersionStr()));

	}
	else hr = S_FALSE; // if here, user canceled.

  // Cleanup the function...
leave_routine:
	SetCursor(m_curArrow);

 // Free the rowset (which will cleanup MSDAIPP on error)...
	RELEASE_INTERFACE(pMsdaippRowset);

  // We'll check for some well known errors, and notity the user. We'll then retry the
  // the prompt so user can correct the URL or retry their settings (or password).
	if (FAILED(hr))
	{
		LPSTR pszPrefix;
		switch (hr)
		{
		case DB_E_TIMEOUT:
		case DB_E_CANNOTCONNECT:
			pszPrefix =
				"We cannot connect to the web folder because the server name is invalid or the\r\n"
				"server is unavailable at this time.";
			break;

		case DB_E_NOTABLE:
		case IPP_E_REDIRECTEDORMOVED:
			pszPrefix = "We cannot connect to the web folder because the folder name\r\n"
				"is invalid or is not supported as either a WEC or DAV share.";
			break;

		case E_ACCESSDENIED:
		case DB_SEC_E_AUTH_FAILED:
			pszPrefix = "You do not have permissions to open a folder on this server.";
			break;

		default:
			pszPrefix = "An error occurred trying to open the folder specified. This may be\r\n"
                "due to an incorrect URL, or bind option, or general problem to properly\r\n"
                "establish a connection.";
		}

	 // Display error message to the user...
        DsoDisplayIPPError(pszPrefix, hr, "Could not open the folder!");

	 // Reset the session and relase any held handles...
		pMsdaippSession->ResetSession();
		CmdCloseFolder();
		goto retrydialog; // retry...
	}

  // Otherwise, folder opened successfully or user canceled. The release of the
  // session object is OK here since open rowset will keep it alive...
	RELEASE_INTERFACE(pMsdaippSession);
	return SUCCEEDED(hr);
}

///////////////////////////////////////////////////////////////////////////////////
// COfficeWebClientApp::CmdCloseFolder
//
//  Called both by user and internally by code. This frees any held objects with
//  should free them on their final release. 
//
STDMETHODIMP_(BOOL) COfficeWebClientApp::CmdCloseFolder()
{
    ODS("COfficeWebClientApp::CmdCloseFolder\n");

	if (IsWindowVisible(m_hwndListView))
	{
		ShowWindow(m_hwndListView, SW_HIDE);
		SendMessage(m_hwndStatus, SB_SETTEXT, 0, (LPARAM)"");
		SendMessage(m_hwndStatus, SB_SETTEXT, 1, (LPARAM)"");
	}

	if (m_pCurrentFolder)
	{
		m_pCurrentFolder->CleanupListView(FALSE);
		while (m_pCurrentFolder->GetParentFolder())
		{
			COfficeWebFolder* pparent = m_pCurrentFolder->GetParentFolder();
			m_pCurrentFolder->Release();
			m_pCurrentFolder = pparent;
		}
	}

	RELEASE_INTERFACE(m_pCurrentFolder);
	RELEASE_INTERFACE(m_pRootFolder);
	return TRUE;
}

///////////////////////////////////////////////////////////////////////////////////
// COfficeWebClientApp::CmdCreateSubFolder
//
//  Lets the user create a sub folder. We use a simple dialog prompt to select a
//  name for the folder. A better approach would be to add an item and then force
//  a label edit in the list view (like you have in Explorer). But, this works well
//  enough for this case. 
//
STDMETHODIMP_(BOOL) COfficeWebClientApp::CmdCreateSubFolder()
{
	BOOL fSuccess = FALSE;
	BSTR bstrNewFolderName;
	CHAR szNewFolder[MAX_PATH];
	LVFINDINFO lvchk;

 // We can't continue unless we have a current folder to edit, and
 // we have to have write access to add a new folder (if open read-only, we
 // will fail later on since rowset is read-only)...
	if ((m_pCurrentFolder) && !(m_fROSession))
	{
		lstrcpy(szNewFolder, "New Folder");
		memset(&lvchk, 0, sizeof(LVFINDINFO));
		lvchk.flags = LVFI_STRING;

retryfoldername:
	 // We display our simple input box dialog to get the name from the user and
	 // then run a quick scan of the list view to make sure an item by that name
	 // doesn't already exist. It is fast to error here on a duplicate name than
	 // send the request all the way to the server...
		if (DialogBoxParam(m_hInstance, MAKEINTRESOURCE(IDD_NEWSUBFOLDER),	
				m_hwndApp, NewFolderNameWndProc, (LONG)&szNewFolder[0])
			&& lstrlen(szNewFolder))
		{
			lvchk.psz = szNewFolder;
			if (ListView_FindItem(m_hwndListView, -1, &lvchk) != -1)
			{
				MessageBox(m_hwndApp, "A folder/file by this name already exists.",
					"New Folder", MB_ICONWARNING);
				goto retryfoldername;
			}

		 // If we have a name it is is not a duplicate, let's convert to Unicode
		 // and create the subfolder...
			bstrNewFolderName = DsoConvertToBSTR(szNewFolder);
			if (bstrNewFolderName)
			{
				HRESULT hr = m_pCurrentFolder->CreateNewSubFolder(bstrNewFolderName);
				fSuccess = SUCCEEDED(hr);
				if (!fSuccess)
				{
					CHAR szbuf[MAX_PATH];
					wsprintf(szbuf, "Unable to make the folder \"%s\" at this time.", szNewFolder);
                    DsoDisplayIPPError(szbuf, hr, "New Folder Error");
				}
				SysFreeString(bstrNewFolderName);
			}
		}
	}

	return fSuccess;
}

///////////////////////////////////////////////////////////////////////////////////
// COfficeWebClientApp::CmdDownloadFile
//
//  Displays a dialog to let user choose a download location for the selected item,
//  and then downloads it using IStream. 
//
STDMETHODIMP_(BOOL) COfficeWebClientApp::CmdDownloadFile()
{
	BOOL fSuccess = FALSE;
	LPMSDAIPP_ROWSETINFO pinfo;
	BSTR  bstrDownloadFile;
	INT idx;

 // We need an active folder...
	CHECK_NULL_RETURN(m_pCurrentFolder, FALSE);
	idx = m_pCurrentFolder->GetSelectedItemIndex();

 // We also need a selected item, and it should be a file (the sample doesn't 
 // support the full download of a folder)...
	if ((idx >= 0) && 
		(pinfo = m_pCurrentFolder->GetRowsetInfo(idx)) &&
		(pinfo->bIsSubFolder == 0))
	{
	 // Get the download path from the user. This is returned as a Unicode path
	 // for OS paths that require it...
		if (SUCCEEDED(DsoGetFileFromUser(m_hwndApp,
			L"Download Location", (OFN_PATHMUSTEXIST|OFN_OVERWRITEPROMPT),
			pinfo->wszDisplayName, TRUE, &bstrDownloadFile)))
		{
		 // Do the download...
			HRESULT hr = m_pCurrentFolder->DownloadFile(idx, bstrDownloadFile);
			fSuccess = SUCCEEDED(hr);
			if (!fSuccess)
			{
				CHAR szBuf[MAX_PATH];
				wsprintf(szBuf,
					"Unable to download the file \"%S\" to the selected location.",
                    pinfo->wszDisplayName);
                DsoDisplayIPPError(szBuf, hr, "Download Error");
			}

			SysFreeString(bstrDownloadFile);
		}
	}
	else MessageBeep(0);

	return fSuccess;
}

///////////////////////////////////////////////////////////////////////////////////
// COfficeWebClientApp::CmdUploadFile
//
//  Allows user to pick a file from the local machine to upload. 
//
STDMETHODIMP_(BOOL) COfficeWebClientApp::CmdUploadFile()
{
	BOOL fSuccess = FALSE;
	BSTR bstrUploadFile;

 // Must have a folder to work with, and not be read-only...
    if ((m_pCurrentFolder) && !(m_fROSession))
    {
	 // Get the file to upload from the user. This can be any file on the OS as
	 // long as we have read access to it...
		if (SUCCEEDED(DsoGetFileFromUser(m_hwndApp,	L"Upload File",
			(OFN_HIDEREADONLY|OFN_FILEMUSTEXIST), NULL, FALSE, &bstrUploadFile)))
		{
		 // Do the upload...
		    HRESULT hr = m_pCurrentFolder->UploadFile(bstrUploadFile);
		    fSuccess = SUCCEEDED(hr);
		    if (!fSuccess)
		    {
                DsoDisplayIPPError(
                    "Unable to upload the file to the web folder.",
                    hr, "Upload Error");
		    }

            SysFreeString(bstrUploadFile);
        }

    }
    else MessageBeep(0);

	return fSuccess;
}

///////////////////////////////////////////////////////////////////////////////////
// COfficeWebClientApp::CmdRenameFile
//
//  Rename a selected file. Not currently implemented.
//
STDMETHODIMP_(BOOL) COfficeWebClientApp::CmdRenameFile()
{
	// TODO: Rename a row using IRowChange...
	return FALSE;
}

///////////////////////////////////////////////////////////////////////////////////
// COfficeWebClientApp::CmdDeleteFile
//
//  Deletes the selected file or folder.
//
STDMETHODIMP_(BOOL) COfficeWebClientApp::CmdDeleteFile()
{
	BOOL fSuccess = FALSE;
	LPMSDAIPP_ROWSETINFO pinfo;
	INT idx;

	CHECK_NULL_RETURN(m_pCurrentFolder, FALSE);
	idx = m_pCurrentFolder->GetSelectedItemIndex();

 // We must have a selected item, but it can be a folder or a file...
	if ((idx >= 0) && 
		(pinfo = m_pCurrentFolder->GetRowsetInfo(idx)))
	{
		CHAR  szPrompt[MAX_PATH];
		LPSTR pszItemToDelete = DsoConvertToMBCS(pinfo->wszDisplayName);

	  // We certainly want to prompt the user before a delete and give full name
	  // of the resource since it will be permanently lost after the delete (no undo)...
		if (pinfo->bIsSubFolder)
		{
			wsprintf(szPrompt,
				"Are you sure you want to permanently delete the folder \"%s\" and all it's contents?", 
				pszItemToDelete);
		}
		else
		{
			wsprintf(szPrompt,
				"Are you sure you want to permanently delete the file \"%s\"?", 
				pszItemToDelete);
		}

	 // Make sure the user says Yes before doing the delete...
		if (MessageBox(m_hwndApp, szPrompt, "Delete", MB_ICONQUESTION|MB_YESNO|MB_DEFBUTTON2) == IDYES)
		{
		 // Delete the item (this could fail if resource is locked by another client)...
			HRESULT hr = m_pCurrentFolder->DeleteItem(idx);
			fSuccess = SUCCEEDED(hr);
			if (!fSuccess)
			{
                DsoDisplayIPPError(
                    "Unable to delete the selected item.", hr, "Delete Error");
			}
		}

		FREE_MEMPOINTER(pszItemToDelete);
	}
	else MessageBeep(0);

	return fSuccess;
}

///////////////////////////////////////////////////////////////////////////////////
// COfficeWebClientApp::CmdSelectAll
//
//  Since this sample only lets you select one item at a time, this is not needed.
//  In the future the sample should be extended to allow multi-select, so this is 
//  here as a place holder. The code would work if we allowed it.
//
STDMETHODIMP_(BOOL) COfficeWebClientApp::CmdSelectAll()
{
	ListView_SetItemState(m_hwndListView, -1, LVIS_SELECTED, LVIS_SELECTED);
	return TRUE;
}

///////////////////////////////////////////////////////////////////////////////////
// COfficeWebClientApp::CmdUpFolder
//
//  Allows the user to navigate up to the preceeding folder (if there is one). All
//  we do is check for a parent folder, make it the current one, and then re-populate
//  the list view. Simple.
//
STDMETHODIMP_(BOOL) COfficeWebClientApp::CmdUpFolder()
{
	if ((m_pCurrentFolder) && 
		(m_pCurrentFolder->GetParentFolder()))
	{
		COfficeWebFolder* pparent = m_pCurrentFolder->GetParentFolder();
		m_pCurrentFolder->Release();
		m_pCurrentFolder = pparent;
        InternalSetStatusBarFolderName();
		return (SUCCEEDED(m_pCurrentFolder->CleanupListView(TRUE)) &&
                SUCCEEDED(m_pCurrentFolder->PopulateListView()));
	}
	return FALSE;
}

///////////////////////////////////////////////////////////////////////////////////
// COfficeWebClientApp::CmdRefreshView
//
//  To refresh we call CleanupListView with TRUE to force a reconnect of the rowset
//  and then re-populate the list view. 
//
STDMETHODIMP_(BOOL) COfficeWebClientApp::CmdRefreshView()
{
	if ((m_pCurrentFolder) && 
		SUCCEEDED(m_pCurrentFolder->CleanupListView(TRUE)))
	{
        InternalSetStatusBarFolderName();
		return SUCCEEDED(m_pCurrentFolder->PopulateListView());
	}
	return FALSE;
}

///////////////////////////////////////////////////////////////////////////////////
// COfficeWebClientApp::CmdSwitchView
//
//  Changes the list view style. 
//
STDMETHODIMP_(BOOL) COfficeWebClientApp::CmdSwitchView(UINT vwid)
{
	DWORD dwStyle, dwView;
	if ((m_hwndListView) && (m_pCurrentFolder))
	{
		dwView = ((2 == vwid) ? LVS_REPORT : (1 == vwid) ? LVS_LIST : LVS_ICON);

		dwStyle = GetWindowLong(m_hwndListView, GWL_STYLE);
		dwStyle &= ~(LVS_ICON|LVS_LIST|LVS_REPORT);
		dwStyle |= dwView;

        SetWindowLong(m_hwndListView, GWL_STYLE, dwStyle);
		UpdateWindow(m_hwndListView);
		return TRUE;
	}
	return FALSE;
}

///////////////////////////////////////////////////////////////////////////////////
// COfficeWebClientApp::InternalOpenSubFolderView
//
//  This internal function is called when we want to navigate down to a subfolder.
//  The id is the index of the item in the list view. 
//
STDMETHODIMP COfficeWebClientApp::InternalOpenSubFolderView(UINT id)
{
	HRESULT hr;
	COfficeWebFolder* pNewFolder;
	CHECK_NULL_RETURN(m_pCurrentFolder, E_FAIL);

 // Like the first open, it might take a bit to get a new folder open
 // so we set the wait cursor for the user...
	SetCursor(m_curWait);

 // All we need to do is ask the current folder to open the folder by the index. It
 // will return the new child folder object which we then set as the new current 
 // folder if the populate is successful. This child will hold on to the parent so
 // we can navigate back up and keep alive the entire session...
	hr = m_pCurrentFolder->OpenSubFolder(id, &pNewFolder);
	if (SUCCEEDED(hr))
	{
	 // Populate the view. If this fails, re-populate the existing
	 // folder (which should work) and return the hr as error...
		hr = pNewFolder->PopulateListView();
		if (SUCCEEDED(hr))
		{
			(m_pCurrentFolder = pNewFolder)->AddRef();
		}
		else m_pCurrentFolder->PopulateListView();

        InternalSetStatusBarFolderName();

	 // Assuming the populate failed, this will self-destory the object
	 // to clean up the memory...
		pNewFolder->Release();
	}
	SetCursor(m_curArrow);
	return hr;
}

///////////////////////////////////////////////////////////////////////////////////
// COfficeWebClientApp::InternalDisplayFileProps
//
//  This internal function is called when we want to display the file properties
//  of the item passed.
//
STDMETHODIMP COfficeWebClientApp::InternalDisplayFileProps(UINT id)
{
	LPMSDAIPP_ROWSETINFO pinfo;
	HRESULT hr = E_UNEXPECTED;

	CHECK_NULL_RETURN(m_pCurrentFolder, E_FAIL);

  // Get the LPMSDAIPP_ROWSETINFO for the item at id...
	pinfo = m_pCurrentFolder->GetRowsetInfo(id);
	if (pinfo)
    {
	 // Display the dialog and pass the pointer. The dialog init does all
	 // the work reading out the file properties...
        if (DialogBoxParam(m_hInstance, MAKEINTRESOURCE(IDD_FILEPROPS),	
			m_hwndApp, ShowFilePropWndProc, (LONG)pinfo))
	    {
		 // If the function returns TRUE, the user pressed the Download
		 // button, so call the menu function on their behalf. The selected
		 // item in the list view should not change, so this should be safe.
            CmdDownloadFile();
		    hr = S_OK;
	    }
        else hr = S_FALSE;
    }

	return hr;
}

///////////////////////////////////////////////////////////////////////////////////
// COfficeWebClientApp::InternalSetStatusBarFolderName
//
//  Updates the folder name in the status bar.
//
STDMETHODIMP_(void) COfficeWebClientApp::InternalSetStatusBarFolderName()
{
    CHAR szT[MSDAIPP_MAX_URL_LENGTH + 20];
    szT[0] = 0;

    if (m_pCurrentFolder)
    {
        LPSTR psz = m_pCurrentFolder->GetFolderName();
		if ((psz) && (*psz))
            wsprintf(szT, ((m_fROSession) ? "%s  (read-only)" : "%s"), psz);
    }

    SendMessage(m_hwndStatus, SB_SETTEXT, 0, (LPARAM)szT);
}

///////////////////////////////////////////////////////////////////////////////////
// Main Window Message Handlers
//
// Basic Win32 message handler functions for the host...
//
void COfficeWebClientApp::OnAppQuit()
{
    ODS("COfficeWebClientApp::OnAppQuit\n");

 // Close the current folder...
	if (m_pCurrentFolder) CmdCloseFolder();

 // Destroy our windows...
	if (m_hwndListView) DestroyWindow(m_hwndListView);
    if (m_hwndStatus)   DestroyWindow(m_hwndStatus);
    if (m_hwndApp)      DestroyWindow(m_hwndApp);
	if (m_hmnuMainMenu) DestroyMenu(m_hmnuMainMenu);

 // And the image lists...
	if (m_himlSmIcons)  ImageList_Destroy(m_himlSmIcons);
	if (m_himlIcons)	ImageList_Destroy(m_himlIcons);

    return;
}

void COfficeWebClientApp::OnPaint(HDC hDC, LPRECT lpUpdateRect)
{
    RECT rcClient; GetClientRect(m_hwndApp, &rcClient);
    int mapmode = SetMapMode(hDC, MM_TEXT);

    HPEN hpenWhite = (HPEN)GetStockObject(WHITE_PEN);
    HPEN hpenLtGray = CreatePen(PS_SOLID, 1, 0x00c0c0c0);
    HPEN hpenDkGray = CreatePen(PS_SOLID, 1, 0x00808080);
    HPEN hpenOld = (HPEN)SelectObject(hDC, hpenDkGray);

    HBRUSH hbshLtGray = (HBRUSH)GetStockObject(LTGRAY_BRUSH);
    HBRUSH hbshDkGray = CreateSolidBrush(0x00808080);
    HBRUSH hbshOld = (HBRUSH)SelectObject(hDC, hbshLtGray);

 // Draw the menu separator...
    MoveToEx(hDC, 0, 0, NULL); LineTo(hDC, rcClient.right, 0);
    SelectObject(hDC, hpenWhite);
    MoveToEx(hDC, 0, 1, NULL); LineTo(hDC, rcClient.right, 1);
    SelectObject(hDC, hpenLtGray);
    MoveToEx(hDC, 0, 2, NULL); LineTo(hDC, rcClient.right, 2);

 // Draw sunken border around MDI client area...
    RECT rcMDIClient;
	SetRect(&rcMDIClient, 1, 3, rcClient.right, (rcClient.bottom - SBAR_HEIGHT));

    DrawEdge(hDC, &rcMDIClient, EDGE_SUNKEN, BF_RECT);

 // Delete objects we created here (not stock objects)...
    DeleteObject(hpenLtGray);
    DeleteObject(hpenDkGray);
    DeleteObject(hbshDkGray);

 // Restore DC to original condition...
    SelectObject(hDC, hpenOld);
    SelectObject(hDC, hbshOld);
    SetMapMode(hDC, mapmode);
    return;
}

void COfficeWebClientApp::OnSize(UINT State, int cx, int cy)
{
	INT rgScrollParts[3];
    ODS("COfficeWebClientApp::OnSize()\n");

 // If we are not minimized...
    if (!IsIconic(m_hwndApp))
	{
	 // Set the list view and status bar correctly on the window...
		SetWindowPos(m_hwndStatus, NULL, 0, (cy - SBAR_HEIGHT), cx, SBAR_HEIGHT, SWP_NOACTIVATE);  
		SetWindowPos(m_hwndListView, NULL, 3, 5, (cx - 6), (cy - (SBAR_HEIGHT + 8)), SWP_NOACTIVATE);  
	
	 // Then set the "parts" of the status bar based on the current width...
		rgScrollParts[0] = (cx - 240); rgScrollParts[1] = (cx - 180); rgScrollParts[2] = -1;
		SendMessage(m_hwndStatus, SB_SETPARTS, 3, (LPARAM)&rgScrollParts[0]);
	}
    return;
}

void COfficeWebClientApp::OnInitMenuPopup(HMENU hMenu, UINT uItem, BOOL fSystemMenu)
{
 // Just before a popup menu, we should enable or disable items depending on whether
 // there is a folder open or not. In a real app this would be more fancy. Here we just
 // handle two states -- enabled or not...
	UINT uEnableFlags = (MF_BYCOMMAND | MF_ENABLED);
	UINT uDisableFlags = (MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);

 // Item enabled when we have a folder...
    UINT uCurStateR = ((m_pCurrentFolder) ? uEnableFlags : uDisableFlags);
 // Item enabled when the folder has write access...
    UINT uCurStateRW = (((m_pCurrentFolder) && !(m_fROSession)) ? uEnableFlags : uDisableFlags);
 // Item enabled when a folder item is selected...
    UINT uCurStateRS = (((m_pCurrentFolder) && (m_pCurrentFolder->GetSelectedItemIndex() != -1)) ? uEnableFlags : uDisableFlags);
 // Item enabled when a folder item is selected and we have write access...
    UINT uCurStateRWS = (((m_pCurrentFolder) && (m_pCurrentFolder->GetSelectedItemIndex() != -1) && !(m_fROSession)) ? uEnableFlags : uDisableFlags);

	if (hMenu == GetSubMenu(m_hmnuMainMenu, 0))
	{
        EnableMenuItem(hMenu, IDM_CLOSEFOLDER,    uCurStateR);
        EnableMenuItem(hMenu, IDM_NEWSUBFOLDER,   uCurStateRW);
	}
	else if (hMenu == GetSubMenu(m_hmnuMainMenu, 1))
	{
        EnableMenuItem(hMenu, IDM_DOWNLOADFILE,   uCurStateRS);
        EnableMenuItem(hMenu, IDM_UPLOADFILE,     uCurStateRW);
        EnableMenuItem(hMenu, IDM_DELETEFILE,     uCurStateRWS);
      //EnableMenuItem(hMenu, IDM_RENAMEFILE,     uCurStateRWS);
      //EnableMenuItem(hMenu, IDM_SELECTALL,      uCurStateR);
	}
	else  if (hMenu == GetSubMenu(m_hmnuMainMenu, 2))
	{
		EnableMenuItem(hMenu, IDM_UPFOLDER,       uCurStateR);
        EnableMenuItem(hMenu, IDM_VIEWICON,       uCurStateR);
        EnableMenuItem(hMenu, IDM_VIEWLIST,       uCurStateR);
        EnableMenuItem(hMenu, IDM_VIEWDETAILS,    uCurStateR);
        EnableMenuItem(hMenu, IDM_ARRANGE_NAME,   uCurStateR);
        EnableMenuItem(hMenu, IDM_REFRESHVIEW,    uCurStateR);
	}
    return;
}

void COfficeWebClientApp::OnSetFocus()
{
 // Forward focus to the list view if it is visible...
	if ((m_pCurrentFolder) && IsWindowVisible(m_hwndListView))
		SetFocus(m_hwndListView);
}

BOOL COfficeWebClientApp::OnCommand(int id, HWND hwndCtl, UINT codeNotify)
{
 // Handler for basic menu commands...

    switch (id)
    {
  ////////////////////////////////////////////////////////
  // Folder Menu
  //
    case IDM_OPENFOLDER:   CmdOpenFolder();      break;
    case IDM_CLOSEFOLDER:  CmdCloseFolder();     break;
	case IDM_NEWSUBFOLDER: CmdCreateSubFolder(); break;
    case IDM_APPEXIT:      SendMessage(m_hwndApp, WM_CLOSE, 0, 0); break;

  ////////////////////////////////////////////////////////
  // File Menu 
  //
    case IDM_DOWNLOADFILE: CmdDownloadFile(); break;
    case IDM_UPLOADFILE:   CmdUploadFile();   break;
    case IDM_RENAMEFILE:   CmdRenameFile();   break;
    case IDM_DELETEFILE:   CmdDeleteFile();   break;
    case IDM_SELECTALL:    CmdSelectAll();    break;

  ////////////////////////////////////////////////////////
  // View Menu 
  //
	case IDM_UPFOLDER:     CmdUpFolder();     break;
    case IDM_REFRESHVIEW:  CmdRefreshView();  break;
    case IDM_VIEWICON:
    case IDM_VIEWLIST:
    case IDM_VIEWDETAILS:  CmdSwitchView((UINT)(id - IDM_VIEWICON)); break;

  ////////////////////////////////////////////////////////
  // Help Menu 
  //
    case IDM_HELPABOUT:
		{
			MessageBox(m_hwndApp,  
				"Office WebFolder Client Application Sample (for MSDAIPP)\r\n"
				"Copyright (c)1999-2003; Microsoft Corporation. All rights reserved.\r\n\r\n"
				"This sample is provided \"as is\" for demonstration purposes only.\r\n"
				"Written by Microsoft Developer Support Office Integration.\r\n",
				"About OWebFolder", MB_ICONINFORMATION);
		}
        break;

    default:
      return FALSE;

    }

    return TRUE;
}

BOOL COfficeWebClientApp::OnNotify(int id, LPNMHDR pnmhdr)
{
	BOOL fHandled = FALSE;

 // We handle a few WM_NOTIFY messages from the list view....
	if ((m_pCurrentFolder) && (pnmhdr->hwndFrom == m_hwndListView))
	{
		switch (pnmhdr->code)
		{
		case NM_DBLCLK:
		case NM_RETURN:
		 // If the user double-clicks or hits the return key, get the selected
		 // item and either open it or display its properties...
			id = m_pCurrentFolder->GetSelectedItemIndex();
			if (id >= 0)
			{
				if (m_pCurrentFolder->IsItemSubFolder(id))
				{
					if (FAILED(InternalOpenSubFolderView(id)))
						MessageBox(m_hwndApp, "Unable to open sub folder!", "Error", MB_ICONHAND);
				}
				else
				{
					if (FAILED(InternalDisplayFileProps(id)))
						MessageBox(m_hwndApp, "Unable to show file properties!", "Error", MB_ICONHAND);
				}
				fHandled = TRUE;
			}
			break;

		case LVN_KEYDOWN:
		 // If the user hits the backspace key while in a subfolder, we'll go back up
		 // to the parent folder (just as you do in Explorer)...
			if ((((LPNMLVKEYDOWN)pnmhdr)->wVKey == VK_BACK) && 
				(m_pCurrentFolder->GetParentFolder()))
			{
				CmdUpFolder();
				fHandled = TRUE;
			}
			break;

		case LVN_GETDISPINFO:
		 // When in Report view, we need to provide additional information to the list view...
			m_pCurrentFolder->SetDisplayInfo((NMLVDISPINFO*)pnmhdr);
			fHandled = TRUE;
			break;

		}
	}
	return fHandled;
}

///////////////////////////////////////////////////////////////////////////////////
// ClientAppWndProc  -- Main App Window Proc
//
//  Handles all messages for the host app window and list view.
//
LRESULT CALLBACK COfficeWebClientApp::ClientAppWndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
 // If we can't get the app, something very wrong. Just exit w/ DefWinProc...
    if (g_theApp == NULL) goto exit_defwndproc;

	switch (iMsg)
	{
	case WM_PAINT:
		{
		PAINTSTRUCT ps;
		BeginPaint(hwnd, &ps);
		g_theApp->OnPaint(ps.hdc, &ps.rcPaint);
		EndPaint(hwnd, &ps);
		}
		break;

	case WM_COMMAND:
		if (g_theApp->OnCommand((int)LOWORD(wParam), (HWND)lParam, (UINT)HIWORD(wParam)))
			return 0;
		break;

	case WM_NOTIFY:
		if (g_theApp->OnNotify((int)wParam, (LPNMHDR)lParam))
			return 0;
		break;

	case WM_SIZE:
		g_theApp->OnSize((UINT)wParam, (int)LOWORD(lParam), (int)HIWORD(lParam));
		break;

	case WM_CLOSE:
		g_theApp->OnAppQuit();
		break;

	case WM_INITMENUPOPUP:
		g_theApp->OnInitMenuPopup((HMENU)wParam, (UINT)LOWORD(lParam), (BOOL)HIWORD(lParam));
		break;

	case WM_GETMINMAXINFO:
		{
		LPMINMAXINFO lpMinMaxInfo = (LPMINMAXINFO)lParam;
		lpMinMaxInfo->ptMinTrackSize.x = 400;
		lpMinMaxInfo->ptMinTrackSize.y = 300;
		}
		break;

	case WM_SETFOCUS:
		g_theApp->OnSetFocus();
		break;

	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	}

exit_defwndproc:
	return DefWindowProc(hwnd, iMsg, wParam, lParam);
}

///////////////////////////////////////////////////////////////////////////////////
// OpenFolderWndProc -- Window Proc for OpenFolder dialog
//
//  Does the basic setup for the OpenFolder dialog, and copies all the user choices
//  into the LP_MSDAIPP_SESSIONINFO passed during creation.
//
BOOL CALLBACK COfficeWebClientApp::OpenFolderWndProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
    switch (iMsg)
	{
    case WM_INITDIALOG:
		{	
		 // Set the bind props for this dialog window...
			LP_MSDAIPP_SESSIONINFO pbndps = (LP_MSDAIPP_SESSIONINFO)(lParam);
			SetWindowLong(hDlg, GWL_USERDATA, (LONG)pbndps);
			
			HWND hwndctl = GetDlgItem(hDlg, IDC_URL);
			if (hwndctl)
			{
				if (pbndps->szDataSource[0] != '\0')
				{
					SendMessage(hwndctl, WM_SETTEXT, 0, (LPARAM)pbndps->szDataSource);
					SendMessage(hwndctl, EM_SETSEL, 0, -1);
				}
				else
				{
					SendMessage(hwndctl, WM_SETTEXT, 0, (LPARAM)"http://");
					SendMessage(hwndctl, EM_SETSEL, 7, 7);
				}
				SetFocus(hwndctl);
			}

			hwndctl = GetDlgItem(hDlg, IDC_PROVIDERS);
			if (hwndctl)
			{
				SendMessage(hwndctl, CB_ADDSTRING, 0, (LPARAM)"Automatic Protocol Discovery");
				SendMessage(hwndctl, CB_ADDSTRING, 0, (LPARAM)"FrontPage Web Extender Client (WEC)");
				SendMessage(hwndctl, CB_ADDSTRING, 0, (LPARAM)"Distributed Authoring and Versioning (DAV)");
				SendMessage(hwndctl, CB_SETCURSEL, 0, 0);
			}

			SetDlgItemText(hDlg, IDC_LOCKOWNER, pbndps->szLockOwner);

			hwndctl = GetDlgItem(hDlg, IDC_ENCODETYPE);
			if (hwndctl)
			{
				SendMessage(hwndctl, CB_ADDSTRING, 0, (LPARAM)"Unicode");
				SendMessage(hwndctl, CB_ADDSTRING, 0, (LPARAM)"Multi-Byte (MBCS) Non-Canonicalized");
				SendMessage(hwndctl, CB_ADDSTRING, 0, (LPARAM)"Multi-Byte (MBCS) Canonicalized");
				SendMessage(hwndctl, CB_ADDSTRING, 0, (LPARAM)"UTF-8 Non-Canonicalized");
				SendMessage(hwndctl, CB_ADDSTRING, 0, (LPARAM)"UTF-8 Canonicalized");
				SendMessage(hwndctl, CB_SETCURSEL, 0, 0);
			}

			if (pbndps->uiProviderVersion < 2)
			{
				for (int i = IDC_BIND_CUSTUSERAGENT; i <= IDC_ENCODETYPE; i++)
					EnableWindow(GetDlgItem(hDlg, i), FALSE);
			}
		}
		break;

    case WM_COMMAND:
		{
			switch (LOWORD(wParam))
			{
			case IDOK:
				{
					LP_MSDAIPP_SESSIONINFO pbndps = 
						(LP_MSDAIPP_SESSIONINFO)GetWindowLong(hDlg, GWL_USERDATA);
					if (pbndps)
					{
					 // Set the binding flags for the session...
						DWORD flags = (DBBINDURLFLAG_READ | DBBINDURLFLAG_SHARE_DENY_NONE);

						if (!IsDlgButtonChecked(hDlg, IDC_BIND_OPENREADONLY))
							flags |= (DBBINDURLFLAG_WRITE);

						if (IsDlgButtonChecked(hDlg, IDC_BIND_OUTPUT))
							flags |= DBBINDURLFLAG_OUTPUT;

						pbndps->grfBindFlags = flags;

					 // Copy the URL string and authentication information (do rough check for valid URL)...
						GetDlgItemText(hDlg, IDC_URL, pbndps->szDataSource, MSDAIPP_MAX_URL_LENGTH);
						if ((pbndps->szDataSource[0] == '\0') || (lstrlen(pbndps->szDataSource) < 8))
						{
							MessageBox(hDlg,
								"Please enter a valid URL for the folder name. Make sure it starts with either \"http://\" or \"https://\".",
								"Open Folder", MB_SETFOREGROUND | MB_ICONINFORMATION);
							break;
						}

						GetDlgItemText(hDlg, IDC_LOCKOWNER, pbndps->szLockOwner,MAX_PATH);

					 // Set any MSDAIPP-specific flags for the provider...
						flags = 0;

						if (IsDlgButtonChecked(hDlg, IDC_BIND_CACHEAGRESSIVE))
							flags |= OWF_CACHEAGGRESSIVELY;

						if (IsDlgButtonChecked(hDlg, IDC_BIND_OFFLINE))
							flags |= OWF_TREATASOFFLINE;

						if (IsDlgButtonChecked(hDlg, IDC_BIND_FLUSHINETAUTH))
							flags |= OWF_FLUSHWININETPWCACHE;

						if (IsDlgButtonChecked(hDlg, IDC_BIND_CUSTUSERAGENT))
							flags |= OWF_CUSTOMUSERAGENT;

						if (IsDlgButtonChecked(hDlg, IDC_BIND_DAVLOCKDISCOVERY))
							flags |= OWF_DAV_USELOCKDISCOVERY;

						if (IsDlgButtonChecked(hDlg, IDC_BIND_SHOWWECTHICKET))
							flags |= OWF_WEC_SHOWTHICKETFILES;

						pbndps->grfProviderFlags = flags;
			
					 // Then set the protocol provider...
						switch (SendMessage(GetDlgItem(hDlg, IDC_PROVIDERS), CB_GETCURSEL, 0, 0))
						{
						case 1:	 pbndps->uidProtocolProvider = GUID_WEC_PROVIDER; break;
						case 2:	 pbndps->uidProtocolProvider = GUID_DAV_PROVIDER; break;
						default: pbndps->uidProtocolProvider = GUID_NULL;
						}

						switch (SendMessage(GetDlgItem(hDlg, IDC_ENCODETYPE), CB_GETCURSEL, 0, 0))
						{
						case 1:	 pbndps->grfEncodingType = DBPROPVAL_UE_URL_MBS; break;
						case 2:	 pbndps->grfEncodingType = DBPROPVAL_UE_URL_MBS | DBPROPVAL_UE_URL_CANONICALIZED; break;
						case 3:	 pbndps->grfEncodingType = DBPROPVAL_UE_URL_UTF8; break;
						case 4:	 pbndps->grfEncodingType = DBPROPVAL_UE_URL_UTF8 | DBPROPVAL_UE_URL_CANONICALIZED; break;
						default: pbndps->grfEncodingType = DBPROPVAL_UE_URL_UNICODE;
						}
					}

				}
				EndDialog(hDlg, TRUE);
				return TRUE;

			case IDCANCEL:
				EndDialog(hDlg, FALSE);
				return TRUE;
			}
		}
		break;
    }

    return FALSE;
}

///////////////////////////////////////////////////////////////////////////////////
// ShowFilePropWndProc -- Window Proc for FileProperties dialog
//
//  Takes the LPMSDAIPP_ROWSETINFO passed in and displays it properties in the dialog.
//
BOOL CALLBACK COfficeWebClientApp::ShowFilePropWndProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
    switch (iMsg)
	{
    case WM_INITDIALOG:
		{
			LPMSDAIPP_ROWSETINFO pfileinfo = (LPMSDAIPP_ROWSETINFO)(lParam);

			LPSTR psz = DsoConvertToMBCS(pfileinfo->wszDisplayName);
			if (psz) {SetDlgItemText(hDlg, IDC_FPROP_NAME, psz); MemFree(psz);}

			psz = DsoConvertToMBCS(pfileinfo->wszURL);
			if (psz) {SetDlgItemText(hDlg, IDC_FPROP_URL, psz); MemFree(psz);}

			psz = DsoConvertToMBCS(pfileinfo->wszContentType);
			if (psz) {SetDlgItemText(hDlg, IDC_FPROP_TYPE, psz); MemFree(psz);}

			psz = GetFormattedSize(pfileinfo->ddwStreamSize);
			if (psz) {SetDlgItemText(hDlg, IDC_FPROP_SIZE, psz); MemFree(psz);}

			psz = GetFormattedDate(pfileinfo->ftCreateTime);
			if (psz) {SetDlgItemText(hDlg, IDC_FPROP_DATECREATE, psz); MemFree(psz);}

			psz = GetFormattedDate(pfileinfo->ftLastModified);
			if (psz) {SetDlgItemText(hDlg, IDC_FPROP_DATEMODIFIED, psz); MemFree(psz);}

			if (pfileinfo->bIsReadOnly)
				CheckDlgButton(hDlg, IDC_FPROP_READONLY, BST_CHECKED);

			if (pfileinfo->bIsHidden)
				CheckDlgButton(hDlg, IDC_FPROP_HIDDEN, BST_CHECKED);

			if (pfileinfo->bIsMarkedOffline)
				CheckDlgButton(hDlg, IDC_FPROP_MARKEDOFFLINE, BST_CHECKED);
		}
		break;

    case WM_COMMAND:
		{
			switch (LOWORD(wParam))
			{
            case IDC_DOWNLOAD:
                EndDialog(hDlg, TRUE);
                return TRUE;

			case IDOK:
			case IDCANCEL:
				EndDialog(hDlg, FALSE);
				return TRUE;
			}
		}
		break;
    }

    return FALSE;
}

///////////////////////////////////////////////////////////////////////////////////
// NewFolderNameWndProc -- Window Proc for NewFolder dialog
//
//  Gets the name for a new folder.
//
BOOL CALLBACK COfficeWebClientApp::NewFolderNameWndProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
	LPSTR pszName;

    switch (iMsg)
	{
    case WM_INITDIALOG:
		{
			pszName = (LPSTR)(lParam);
			if (pszName)
			{
				SetWindowLong(hDlg, GWL_USERDATA, (LONG)pszName);
				
				HWND hwndctl = GetDlgItem(hDlg, IDC_NEWF_NAME);
				if (hwndctl)
				{
					SendMessage(hwndctl, WM_SETTEXT, 0, (LPARAM)pszName);
					SendMessage(hwndctl, EM_SETSEL, 0, -1);
					SetFocus(hwndctl);
				}
				*pszName = '\0';
			}
		}
		break;

    case WM_COMMAND:
		{
			switch (LOWORD(wParam))
			{
			case IDOK:
				{
					pszName = (LPSTR)GetWindowLong(hDlg, GWL_USERDATA);
					if (pszName)
						GetDlgItemText(hDlg, IDC_NEWF_NAME, pszName, MAX_PATH);
				}
				EndDialog(hDlg, TRUE);
				return TRUE;

			case IDCANCEL:
				EndDialog(hDlg, FALSE);
				return TRUE;
			}
		}
		break;
    }

    return FALSE;
}

///////////////////////////////////////////////////////////////////////////////////
// WINMAIN. Application start point.
//
int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR pszCmdLine, int nCmdShow)
{
    WPARAM  wRet = (WPARAM)-1;

 // Initialize COM libraries - we run apartment threaded...
    HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
	RETURN_ON_ERROR(hr, "CoInitializeEx failed!");

 // Create the main app and initialize. If successful, spin in 
 // the message loop.  wRet is the exit code.
	g_theApp = new COfficeWebClientApp(hInstance);
    if ((g_theApp) && (g_theApp->InitApplication(pszCmdLine, nCmdShow)))
        wRet = g_theApp->MessageLoop();

 // Free the main object...
	FREE_MEMPOINTER(g_theApp);

 // Goodbye cruel world!
    CoUninitialize();
	return wRet;
}



